const net = require("net");
const EventEmitter = require("events");

class TcpClient extends EventEmitter {
  constructor(ip, port, id, type, status, beUsed, timeout = 60000) {
    super();
    this.ip = ip;
    this.port = port;
    this.id = id;
    this.type = type;
    this.status = status;
    this.beUsed = beUsed;
    this.client = null;

    this.reconnectInterval = null;
    this.connectTimer = null;
    this.isConnected = false;
    this.reconnectAttempts = 0;
    this.MAX_RECONNECT_ATTEMPTS = 10;
    this.INITIAL_RECONNECT_DELAY = 2000;
    this.MAX_RECONNECT_DELAY = 6000;
    this.connectionTimeout = timeout || 60000;
    this.isConnecting = false;
    this.isClosed = false;
    this.isMaxConnected = false;

    this.connect();
  }

  connect() {
    if (this.isConnecting || this.isConnected) {
      return;
    }
    this.isConnecting = true;

    this.connectionStartTime = Date.now();
    this.isConnectionEmitted = false;

    // 清理旧连接
    if (this.client) {
      this.client.removeAllListeners();
      this.client = null;
    }

    this.client = net.createConnection(
      { port: this.port, host: this.ip },
      () => {
        console.log("创建了tcp 连接");
        if (!this.isConnectionEmitted) {
          this.isConnected = true;
          this.reconnectAttempts = 0;
          this.status = "1";
          clearTimeout(this.reconnectInterval);
          this.emit("connected", {
            id: this.id,
            status: this.status,
            ip: this.ip,
            port: this.port,
            type: this.type,
            beUsed: this.beUsed,
            MAX_RECONNECT_ATTEMPTS: this.MAX_RECONNECT_ATTEMPTS / 1 - 1,
          });
          clearTimeout(this.connectTimer);
          this.isConnectionEmitted = true;
        }
        this.isConnecting = false;
      }
    );

    // 设置连接超时
    if (this.client && !this.connectTimer) {
      this.connectTimer = this.client.setTimeout(this.connectionTimeout, () => {
        if (!this.isConnected && this.client) {
          console.log("tcp协议连接强制断开", this.client);
          this.client.destroy();
          this.status = "0";
          this.emit("timeout", {
            id: this.id,
            error: "Connection timeout",
            status: this.status,
            ip: this.ip,
            port: this.port,
            MAX_RECONNECT_ATTEMPTS: this.MAX_RECONNECT_ATTEMPTS / 1 - 1,
          });
          this.startReconnect();
        }
        this.isConnecting = false;
      });
    }

    // 绑定事件监听器
    this.client.on("error", (err) => {
      console.error(`[Error] Client ${this.id} error: ${err.message}`);
      this.isConnected = false;
      this.status = "0";
      this.emit("error", {
        id: this.id,
        error: err.message,
        status: this.status,
        ip: this.ip,
        port: this.port,
        type: this.type,
        beUsed: this.beUsed,
      });
      this.startReconnect();
      this.isConnecting = false;
    });

    this.client.on("close", () => {
      console.log(`[Close] Client ${this.id} disconnected`);
      if (!this.isClosed) {
        this.isClosed = true;
        this.isConnected = false;
        this.status = "0";
        this.emit("close", {
          id: this.id,
          port: this.port,
          ip: this.ip,
          type: this.type,
          status: this.status,
          beUsed: this.beUsed,
          MAX_RECONNECT_ATTEMPTS: this.MAX_RECONNECT_ATTEMPTS / 1 - 1,
        });
        this.startReconnect();
        this.isConnecting = false;
      }
    });
  }

  startReconnect() {
    if (this.reconnectAttempts < this.MAX_RECONNECT_ATTEMPTS) {
      const delay = Math.min(
        this.INITIAL_RECONNECT_DELAY * Math.pow(2, this.reconnectAttempts),
        this.MAX_RECONNECT_DELAY
      );
      console.log(`[Reconnect] Client ${this.id} will reconnect in ${delay}ms`);
      this.reconnectInterval = setTimeout(() => {
        this.reconnectAttempts++;
        this.connect();
      }, delay);
    } else {
      if (!this.isMaxConnected) {
        this.isMaxConnected = true;
        this.isConnected = false;
        this.status = "0";
        this.isConnecting = false;
        console.error(
          `[Reconnect] Client ${this.id} max reconnect attempts reached`
        );
        this.emit("maxReconnects", {
          id: this.id,
          error: "max reconnect attempts reached",
          status: this.status,
          ip: this.ip,
          port: this.port,
          MAX_RECONNECT_ATTEMPTS: this.MAX_RECONNECT_ATTEMPTS / 1 - 1,
        });
        this.isMaxConnected = false;
      }
    }
  }

  sendMessage(message) {
    return new Promise((resolve, reject) => {
      if (!this.isConnected) {
        return reject(new Error("Client is not connected"));
      }

      const onData = (data) => {
        this.client.removeListener("data", onData);
        resolve({ id: this.id, data: data.toString() });
        this.emit("messageSent", {
          id: this.id,
          data: data.toString(),
          message,
        });
      };

      this.client.once("data", onData);

      this.client.write(message, (err) => {
        if (err) {
          this.client.removeListener("data", onData);
          reject(err);
        }
      });
    });
  }

  destroy() {
    clearTimeout(this.reconnectInterval);
    clearTimeout(this.connectTimer);

    if (this.client) {
      this.client.removeAllListeners();
      this.client.destroy();
      this.client = null;
    }

    this.removeAllListeners();
    this.isConnecting = false;
  }

  manualReconnect() {
    clearTimeout(this.reconnectInterval);
    this.reconnectAttempts = 0;
    this.connect();
  }

  getConnectionStatus() {
    return {
      id: this.id,
      isConnected: this.isConnected,
      reconnectAttempts: this.reconnectAttempts,
      ip: this.ip,
      port: this.port,
      type: this.type,
      status: this.status,
      beUsed: this.beUsed,
      MAX_RECONNECT_ATTEMPTS: this.MAX_RECONNECT_ATTEMPTS / 1 - 1,
    };
  }
}

module.exports = TcpClient;
